package com.ctrip.cap.monitor.screenshot;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.imageio.ImageIO;
import javax.imageio.stream.FileImageInputStream;

import com.ctrip.cap.client.RunAtServiceClient;
import com.ctrip.cap.client.impl.CapRunAtDataServiceClientImp;
import com.ctrip.cap.domain.LogSnapShot;
import com.ctrip.cap.client.property.CapClientProperties;
import com.ctrip.cap.device.android.AndroidDevice;
import com.ctrip.cap.monitor.common.Constants;
import com.ctrip.cap.monitor.common.TaskAdapter;
import com.ctrip.cap.monitor.utils.ImageScale;
import com.ctrip.cap.monitor.utils.LogUtil;

public class ScreenShotTask extends TaskAdapter implements Runnable {
	private static final String CMD_SCREEN_SHOT = "adb -s %s shell /system/bin/screencap -p /mnt/sdcard/%s.png";
	private static final String CMD_PULL = "adb -s %s pull /mnt/sdcard/%s.png %s.png";
	private static final String PATH = "/img/";
	private static final String TEMP_NAME = "temp";
	private static final String EXT = ".png";

	private ExecutorService mImageUploadService;
	private volatile boolean isUploadFinish;
	private Object mLock;

	static {
		URL str = Constants.class.getResource("/");
		String rootPath = str.getPath();
		File file = new File(rootPath + PATH);
		LogUtil.info("file:" + file.getAbsolutePath() + " create!");
		if (!file.exists()) {
			file.mkdir();
			LogUtil.info("file:" + file.getAbsolutePath() + " created!");
		}
	}

	public ScreenShotTask(AndroidDevice device, AtomicBoolean isStart) {
		super(device, isStart);
		mLock = new Object();
		mImageUploadService = Executors.newSingleThreadExecutor();
		isUploadFinish = true;
	}

	@Override
	public void run() {
		if (mDevice == null) {
			return;
		}
		URL str = Constants.class.getResource("/");
		String rootPath = str.getPath();
		File path = new File(rootPath + PATH);
		Process p;
		Runtime rt = Runtime.getRuntime();
		int count = 0;
		long start, total = 0;
		isStop = false;
		LogUtil.info(mDevice.getSerialNumber() + " screenshot run! -- ");
		while (!isStop) {
			if (!isStart.get()) {
				try {
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException e) {
					LogUtil.error(e);
				}
				continue;
			}

			count++;
			start = System.currentTimeMillis();

			String sn = mDevice.getSerialNumber();
			String name = sn.replace(":", "") + TEMP_NAME;
			try {
				String cmd = String.format(CMD_SCREEN_SHOT, sn, name);
				p = rt.exec(cmd, null, path);
				p.waitFor();
				cmd = String.format(CMD_PULL, sn, name, name);
				p = rt.exec(cmd, null, path);
				p.waitFor();
			} catch (IOException | InterruptedException e) {
				LogUtil.error(e);
			}

			if (!isUploadFinish) {
				synchronized (mLock) {
					try {
						mLock.wait();
					} catch (InterruptedException e) {
						LogUtil.error(e);
					}
				}
			}

			File src = new File(rootPath + PATH + name + EXT);
			File dist = new File(rootPath + PATH + sn.replace(":", "") + EXT);
			try {
				if (compress(src, dist)) {
					mImageUploadService.execute(new UploadTask(dist));
				}
			} catch (IOException | NullPointerException e) {
				LogUtil.error(e);
			}

			long tmp = System.currentTimeMillis() - start;

			LogUtil.info(mDevice.getSerialNumber()
					+ " screenshot success ! -- " + tmp + " ms.  --- "
					+ Thread.currentThread().getName());
			total += tmp;
			if (count == 10) {
				LogUtil.info(mDevice.getSerialNumber() + " 10 frame cost "
						+ (total / 10000.0) + " s.");
				count = 0;
				total = 0;
			}
		}
	}

	private static boolean compress(File src, File dest) throws IOException {
		LogUtil.info("Compress Picture's task  start");
		BufferedImage img = ImageIO.read(new FileImageInputStream(src));
		if (img == null) {
			return false;
		}
		FileOutputStream fos = new FileOutputStream(dest);
		BufferedImage newImg = new BufferedImage(img.getWidth(),
				img.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
		Graphics g = newImg.createGraphics();
		g.drawImage(img, 0, 0, newImg.getWidth(), newImg.getHeight(), null);
		g.dispose();
		// 使用到了sun包， eclipse不建议使用，但是可以设置忽略
		// window-preferences-java-compiler-errors/warnings
		// -deprecated and restricted api - forbidden reference - warning
		/*
		 * JPEGEncodeParam param = JPEGCodec.getDefaultJPEGEncodeParam(newImg);
		 * param.setQuality(0.25f, false);
		 * JPEGCodec.createJPEGEncoder(fos).encode(newImg, param); fos.close();
		 */

		int w = newImg.getWidth(), h = newImg.getHeight();
		BufferedImage image2 = ImageScale.imageZoomOut(newImg, w, h, true);
		ImageIO.write(image2, "jpeg", fos);
		LogUtil.info("Compress Picture's task  finish");
		return true;
	}

	private class UploadTask implements Runnable {

		private File mFile;

		public UploadTask(File file) {
			mFile = file;
		}

		RunAtServiceClient runAtClient = new CapRunAtDataServiceClientImp();

		@Override
		public void run() {
			isUploadFinish = false;
			if (!Constants.DEBUG) {
				String address = "";
				LogUtil.info("offical state:upload files:" + mFile.getName());
				try {
					String guid = runAtClient.uploadImgFileToServer(mFile
							.getAbsolutePath());
					address = CapClientProperties.CAP_DATA_FILE_DOWNLOAD + "/"
							+ guid + ".png";
				} catch (Exception e1) {
					LogUtil.error(e1);
				}

				if (address != null) {
					LogUtil.info("upload file to " + address);
					LogSnapShot snapShot = new LogSnapShot();
					snapShot.setAddress(address);
					snapShot.setUdid(mDevice.getSerialNumber());
					snapShot.setCreateTime(new Date());
					try {
						LogUtil.info("offical state:upload path to DataBase start------");
						LogUtil.info("before insert " + snapShot);
						runAtClient.uploadImgFileToDB(snapShot);
						LogUtil.info("offical state:upload path to DataBase  finish------");

						LogUtil.info(runAtClient.getClass().toString());

					} catch (Exception e) {
						LogUtil.error(e);
					}
				}
			}
			LogUtil.info(mFile.getName() + " upload finish!");
			isUploadFinish = true;
			synchronized (mLock) {
				mLock.notify();
			}
		}
	}
}
